home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1996 February / EnigmA AMIGA RUN 04 (1996)(G.R. Edizioni)(IT)[!][issue 1996-02][Skylink CD III].iso / earcd / util1 / shell-10.lha / shell-1.0 / src / if.c < prev    next >
C/C++ Source or Header  |  1995-12-07  |  20KB  |  930 lines

  1.  
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <stdlib.h>
  5. #include <dos/rdargs.h>
  6. #include <dos/stdio.h>
  7. #include <proto/dos.h>
  8. #include <proto/utility.h>
  9. #include "util.h"
  10.  
  11. #define NODEBUG 1
  12.  
  13. #ifdef DEBUG
  14. #   define Dputs puts
  15. #else
  16. #   define Dputs(x)
  17. #endif
  18.  
  19. /*
  20.     Now the template to collect all arguments of IF/ELIF/ELSEIF. They
  21.     are the same as for Amiga IF, with these exceptions:
  22.  
  23.     ARGS/M - here I collect everything which is not an argument
  24.         to an option or a flag. eg. the line
  25.  
  26.             IF str1 EQ str2
  27.  
  28.         will yield "str2" as the argument of EQ and "str1"
  29.         will be the first thing in ARGS.
  30.     [/S - This is a trick. By making [ a flag, I can ask for it
  31.         and need not check ARGS.
  32. */
  33. const char arg_template[] = "ARGS/M,NOT/S,WARN/S,ERROR/S,FAIL/S,EQ/K,GT/K,\
  34. GE/K,VAL/S,EXISTS/K,[/S";
  35.  
  36. /*
  37.     This is the structure for the arguments to IF. I don't use
  38.     an LONG[]-Array since this way, it's much easier and error-prone
  39.     to lookup an argument (and I need only ONE cast when I call ReadArgs()
  40.     and not every time when I access the argument.
  41. */
  42. struct IfArgs
  43. {
  44.     char ** args;
  45.     ULONG not;
  46.     ULONG warn;
  47.     ULONG error;
  48.     ULONG fail;
  49.     char * eq;
  50.     char * gt;
  51.     char * ge;
  52.     ULONG  val;
  53.     char * exists;
  54.     ULONG test;
  55. };
  56.  
  57. /*
  58.     This is the second template. It is used if the condition of IF doesn't
  59.     hold. Then I continue reading input (thus effectively read the next
  60.     line of input). The input is split up into garbage (REST) and a
  61.     couple of flags: IF, ELSE, ENDIF, FI, ELIF, ELSEIF. If I find IF,
  62.     I'll note that the next ELSE/ENDIF is meaningless and whenever
  63.     I find an ENDIF/FI, I check if it's the matching one for my IF.
  64.     See below how to continue reading input. Note that I still need
  65.     more commands (ENDIF, ELSE, etc.) since there can be occasions when the
  66.     shell sees them (eg. when I skip the THEN body to look up the optional
  67.     ELSE. When the ELSE branch is executed, the shell will eventually
  68.     hit the ENDIF).
  69. */
  70. const char cont_template[] = "REST/M,IF/S,ELSE/S,ENDIF/S,FI/S,ELIF/S,ELSEIF/S";
  71.  
  72. /* This structure is used to filter the body of the IF. */
  73. struct ContStruct
  74. {
  75.     char ** rest;
  76.     ULONG is_if;
  77.     ULONG is_else;
  78.     ULONG is_endif;
  79.     ULONG is_fi;
  80.     ULONG is_elif;
  81.     ULONG is_elseif;
  82. };
  83.  
  84. /* Prototypes */
  85. int test_amiga (struct IfArgs *);
  86. int test_unix (struct IfArgs *);
  87. int exists (char *);
  88.  
  89. /*
  90.     Main function. argc and argv are ignored since ReadArgs() cooks the
  91.     parameters for me.
  92. */
  93. int main (int argc, char ** argv)
  94. {
  95.     struct IfArgs     arg_struct;   /* The calling parameters            */
  96.     struct ContStruct cont_struct;  /* The contents of a line of the
  97.                     stuff following the IF            */
  98.     struct RDArgs   * rda,        /* Reader for the Arguments to IF        */
  99.             * cont_rda;     /* Reader for the stuff following
  100.                     the IF (see below)                  */
  101.     int           level;        /* Nesting level for IFs            */
  102.     BPTR          old_in,        /* Original value of Input()            */
  103.               current_input; /* *magic* (See below)                 */
  104.     int           cond;        /* The result of the evaluation of
  105.                     the IF condition.            */
  106.  
  107.     /* Clear my args */
  108.     memset (&arg_struct, 0, sizeof(arg_struct));
  109.  
  110.     /* Analyze args */
  111.     if ( (rda = ReadArgs ((char *)arg_template, (LONG *)&arg_struct, NULL)) )
  112.     {
  113.     /* If I have any Amiga-Keywords, I evaluate them Amiga-like */
  114.     if (arg_struct.not || arg_struct.warn || arg_struct.error ||
  115.         arg_struct.fail || arg_struct.val || arg_struct.eq ||
  116.         arg_struct.gt || arg_struct.ge || arg_struct.exists)
  117.     {
  118.         cond = test_amiga (&arg_struct);
  119.     }
  120.     else /* Otherwise, we try the UN*X bourne shell version */
  121.     {
  122.         cond = test_unix (&arg_struct);
  123.     }
  124.  
  125. #ifdef DEBUG
  126.     printf ("IF = %s\n", cond ? "TRUE" : "FALSE");
  127. #endif
  128.  
  129.     /*
  130.         Here is the magic part. If the condition is FALSE, we must
  131.         continue execution after the next ELSE or ENDIF (FI, ELIF,
  132.         etc.). How do we do that ? In fact, it's pretty simple: You can
  133.         continue reading input ! That input doesn't come from stdin,
  134.         though, but from cli->cli_CurrentInput. This stream points into
  135.         the script OR interactive shell where the line came from that
  136.         called us. So I switch stdin to cli_CurrentInput, read until
  137.         the next entry point is found and then I exit - the stream
  138.         handle will then point to the next valid command and the shell
  139.         will happily continue execution. The same happens when an ELSE
  140.         is found. ELSE is just more simple since no condition must be
  141.         evaluated.
  142.     */
  143.     if (!cond)
  144.     {
  145.         LONG current_pos;
  146.         int  c;
  147.  
  148.         level    = 0;    /* No nesting if IF/ELSE/ENDIF's yet    */
  149.  
  150.         /*
  151.         now I fetch the BPTRs to stdin and CurrentInput to swap
  152.         them. Later, when the input has been processed, I'll
  153.         undo that.
  154.         */
  155.         current_input = Cli()->cli_CurrentInput;
  156.         old_in      = Input ();
  157.  
  158.         /* Set new input stream */
  159.         SelectInput (current_input);
  160.  
  161.         /*
  162.         This is heavy magic. ReadArgs() needs and buffered
  163.         stream and the FGetC()/Flush()-Pair provides for that.
  164.         The UnGetC() puts the character back we read.
  165.         */
  166.         c = FGetC (current_input);
  167.         Flush (current_input);
  168.         UnGetC (current_input, c);
  169.  
  170.         for (;;)
  171.         {
  172.         /*
  173.             Remember the current position in case we find an
  174.             ELSEIF. When we hit an ELSEIF, we seek back to the
  175.             beginning of the line and exit. Then the shell will see
  176.             the ELSEIF as the next command and continue with it.
  177.         */
  178.         current_pos = Seek (current_input, 0, OFFSET_CURRENT);
  179.  
  180.         /* Clear the argument structure */
  181.         memset (&cont_struct, 0, sizeof(cont_struct));
  182.  
  183.         /* Read a line of input */
  184.         if (!(cont_rda = ReadArgs ((char *)cont_template,
  185.             (LONG *)&cont_struct, NULL)) )
  186.         {
  187.             PrintFault (IoErr(), "ContReadArgs");
  188.             cond = 10;
  189.             break;
  190.         }
  191.  
  192.         /* now look what we got. */
  193.         if (cont_struct.is_if)
  194.         {
  195.             /* If it's an IF..., we increase the nesting level. */
  196.             level ++;
  197.         }
  198.         else if (cont_struct.is_endif || cont_struct.is_fi ||
  199.             cont_struct.is_else)
  200.         {
  201.             /*
  202.             The IF has ended (either bei ENDIF or ELSE).
  203.             We can handle ELSE here, too since the condition
  204.             was FALSE and thus we have to execute the
  205.             commands in the ELSE branch. Also we stop only
  206.             if level is 0 to allow nesting.
  207.             */
  208.             if (!level)
  209.             break;
  210.  
  211.             level --;
  212.         }
  213.         else if (cont_struct.is_elif || cont_struct.is_elseif)
  214.         {
  215.             /*
  216.             ELSEIF found. Seek back and continue with the
  217.             beginning of the line.
  218.             */
  219.             if (!level)
  220.             {
  221.             if (Seek (current_input, current_pos,
  222.                 OFFSET_BEGINNING) == -1)
  223.             {
  224.                 PrintFault (IoErr(), "Seek back");
  225.                 cond = 10;
  226.             }
  227.             break;
  228.             }
  229.         }
  230.         /*
  231.             If nothing interesting was found, we just ignore it
  232.             (that are the lines which make up the THEN branch.
  233.         */
  234.  
  235.         /* Free memory and read the next line */
  236.         FreeArgs (cont_rda);
  237.         } /* for */
  238.  
  239.         /* No more input but nesting level != 0 ? Something's wrong. */
  240.         if (level)
  241.         {
  242.         fprintf (stderr, "Missing ELSE or ENDIF");
  243.         cond = 10;
  244.         }
  245.  
  246.         /* Undo magic */
  247.         SelectInput (old_in);
  248.  
  249.         /*
  250.         If we had to abort the loop, we might have to free
  251.         memory here.
  252.         */
  253.         if (cont_rda)
  254.         FreeArgs (cont_rda);
  255.     }
  256.  
  257.     /* Free original arguments */
  258.     FreeArgs (rda);
  259.     }
  260.     else
  261.     {
  262.     PrintFault (IoErr(), "ReadArgs() Error");
  263.     cond = 10;
  264.     }
  265.  
  266.     /* Return error code (1 as "IF TRUE" must be filtered out) */
  267.     return (cond < 5) ? 0 : cond;
  268. } /* main */
  269.  
  270. /* Check if a file exists */
  271. int exists (char * fname)
  272. {
  273.     BPTR lock;
  274.     int  cond;
  275.  
  276.     lock = Lock (fname, SHARED_LOCK);
  277.  
  278.     if ( (cond = (lock != NULL)) )
  279.     UnLock (lock);
  280.  
  281.     return cond;
  282. } /* exists */
  283.  
  284. /* Compare the dates of two files. The result will be
  285.  
  286.     -1 if fn1 is older than fn2
  287.      0 if fn1 and fn2 have the same date
  288.      1 if fn1 is newer than fn2
  289.     10 if an error occurred. In this case, a message has been
  290.     printed.
  291. */
  292. int compare_dates (char * fn1, char * fn2)
  293. {
  294.     int cond = 10;
  295.     __aligned struct FileInfoBlock fib1, fib2;
  296.     BPTR lock1, lock2;
  297.  
  298.     /* 1. Lock both files */
  299.     lock1 = Lock (fn1, SHARED_LOCK);
  300.  
  301.     if (lock1)
  302.     {
  303.     lock2 = Lock (fn2, SHARED_LOCK);
  304.  
  305.     if (!lock2)
  306.         PrintFault (IoErr(), fn2);
  307.     }
  308.     else
  309.     PrintFault (IoErr(), fn1);
  310.  
  311.     /* 2. If that worked, Examine() the files */
  312.     if (lock1 && lock2)
  313.     {
  314.     if (!Examine (lock1, &fib1))
  315.     {
  316.         PrintFault (IoErr(), fn1);
  317.     }
  318.     else if (!Examine (lock2, &fib2))
  319.     {
  320.         PrintFault (IoErr(), fn2);
  321.     }
  322.     else
  323.     {
  324.         /*
  325.         Compare the dates and truncate the result (CompareDates()
  326.         can return -15 and the like)
  327.         */
  328.         cond = CompareDates (&fib2.fib_Date, &fib1.fib_Date);
  329.  
  330.         if (cond < 0)
  331.         cond = -1;
  332.         else if (cond > 0)
  333.         cond = 1;
  334.     }
  335.     }
  336.  
  337.     /* 3. Release the files */
  338.     if (lock1)
  339.     {
  340.     UnLock (lock1);
  341.  
  342.     if (lock2)
  343.         UnLock (lock2);
  344.     }
  345.  
  346.     /* Return the result */
  347.     return cond;
  348. } /* compare_dates */
  349.  
  350. /* Evaluate a standard Amiga IF */
  351. int test_amiga (struct IfArgs * args)
  352. {
  353.     int cond;
  354.  
  355.     /* Case 1: Check Result */
  356.     if (args->warn || args->error || args->fail)
  357.     {
  358.     char buffer[32];
  359.     int level;
  360.  
  361.     /* Get the result of the last command */
  362.     GetVar ("RC", buffer, sizeof (buffer), GVF_LOCAL_ONLY);
  363.  
  364.     /* Choose a level */
  365.     if (args->warn)
  366.         level = 5;
  367.     else if (args->error)
  368.         level = 10;
  369.     else
  370.         level = 20;
  371.  
  372.     /* Compare result and the level */
  373.     cond = atoi(buffer) >= level;
  374.     }
  375.     else if (args->exists) /* IF EXISTS */
  376.     {
  377.     cond = exists (args->exists);
  378.     }
  379.     else
  380.     {
  381.     if (args->val) /* Numeric compare: val1 ?? val2 */
  382.     {
  383.         int val1, val2;
  384.  
  385.         if (!args->args)
  386.         {
  387.         fprintf (stderr, "Missing second argument");
  388.         return 10;
  389.         }
  390.  
  391.         /* Note that the FIRST figure is in args[] ! */
  392.         val1 = atoi (args->args[0]);
  393.  
  394.         if (args->eq)
  395.         {
  396.         val2 = atoi (args->eq);
  397.  
  398.         cond = val1 == val2;
  399.         }
  400.         else if (args->gt)
  401.         {
  402.         val2 = atoi (args->gt);
  403.  
  404.         cond = val1 > val2;
  405.         }
  406.         else if (args->ge)
  407.         {
  408.         val2 = atoi (args->ge);
  409.  
  410.         cond = val1 >= val2;
  411.         }
  412.         else
  413.         {
  414.         fprintf (stderr, "Missing arguments");
  415.         return 10;
  416.         }
  417.     }
  418.     else /* String compare: str1 ?? str2*/
  419.     {
  420.         char * str1, * str2;
  421.  
  422.         if (!args->args)
  423.         {
  424.         fprintf (stderr, "Missing second argument");
  425.         return 10;
  426.         }
  427.  
  428.         /* Note that the FIRST string is in args[] ! */
  429.         str1 = args->args[0];
  430.  
  431.         if (args->eq)
  432.         {
  433.         str2 = args->eq;
  434.  
  435.         cond = Stricmp (str1, str2) == 0;
  436.         }
  437.         else if (args->gt)
  438.         {
  439.         str2 = args->gt;
  440.  
  441.         cond = Stricmp (str1, str2) > 0;
  442.         }
  443.         else if (args->ge)
  444.         {
  445.         str2 = args->ge;
  446.  
  447.         cond = Stricmp (str1, str2) >= 0;
  448.         }
  449.         else
  450.         {
  451.         fprintf (stderr, "Missing arguments\n");
  452.         return 10;
  453.         }
  454.     }
  455.     }
  456.  
  457.     /* Return result (negated if neccessary */
  458.     return args->not ? !cond : cond;
  459. } /* test_amiga */
  460.  
  461. int test (char *** args)
  462. {
  463.     char ** arg = *args;
  464.     int cond = -1;
  465.     int not = 0;
  466.     int found_string = FALSE;
  467.     int stop = 0;
  468.  
  469.     while (*arg && cond < 5 && !stop)
  470.     {
  471.     if ((*arg)[0] == '(' && !(*arg)[1])
  472.     {
  473.         arg ++;
  474.         cond = test (&arg);
  475.  
  476.         if (cond < 0)
  477.         {
  478.         fprintf (stderr, "IF: Missing arguments in ( EXPRESSSION )\n");
  479.         cond = 10;
  480.         }
  481.     }
  482.     else if ((*arg)[0] == ')' && !(*arg)[1])
  483.     {
  484.         arg ++;
  485.         break;
  486.     }
  487.     else if ((*arg)[0] == ']' && !(*arg)[1])
  488.     {
  489.         if (arg[1] && !((*arg)[0]==';' && !(*arg)[1]))
  490.         {
  491.         fprintf (stderr, "IF: Unexpected arguments after ]\n");
  492.         cond = 10;
  493.         }
  494.  
  495.         break;
  496.     }
  497.     else if ((*arg)[0] == '!')
  498.     {
  499.         if (!(*arg)[1])
  500.         {
  501.         not = !not;
  502.         arg ++;
  503.         }
  504.         else if ((*arg)[1] == '=')
  505.         {
  506.         if (arg[1] && found_string)
  507.         {
  508.             cond = strcmp (arg[-1], arg[1]) != 0;
  509.             arg += 2;
  510.         }
  511.         else
  512.         {
  513.             if (found_string)
  514.             {
  515.             fprintf (stderr, "IF: Missing second argument to !=\n");
  516.             cond = 10;
  517.             }
  518.             else
  519.             {
  520.             fprintf (stderr, "IF: Missing first argument to !=\n");
  521.             cond = 10;
  522.             }
  523.         }
  524.         }
  525.         else
  526.         {
  527.         fprintf (stderr, "IF: Unknown argument %s\n", *arg);
  528.         cond = 10;
  529.         }
  530.     }
  531.     else if ((*arg)[0] == '=' && !(*arg)[1])
  532.     {
  533.         if (arg[1] && found_string)
  534.         {
  535.         cond = strcmp (arg[-1], arg[1]) == 0;
  536.         arg += 2;
  537.         }
  538.         else
  539.         {
  540.         if (found_string)
  541.         {
  542.             fprintf (stderr, "IF: Missing second argument to =\n");
  543.             cond = 10;
  544.         }
  545.         else
  546.         {
  547.             fprintf (stderr, "IF: Missing first argument to =\n");
  548.             cond = 10;
  549.         }
  550.         }
  551.     }
  552.     else if ((*arg)[0] == '-')
  553.     {
  554.         char * ptr;
  555.  
  556.         ptr = *arg+1;
  557.  
  558.         if (!arg[1])
  559.         {
  560.         fprintf (stderr, "IF: Missing argument to %s\n", *arg);
  561.         cond = 10;
  562.         }
  563.         else
  564.         {
  565.         switch (*ptr)
  566.         {
  567.         case 'a': /* AND */
  568.             if (cond == -1)
  569.             {
  570.             fprintf (stderr, "IF: Missing first argument to -a\n");
  571.             cond = 10;
  572.             }
  573.             else
  574.             {
  575.             if (!cond)
  576.                 stop = 1;
  577.             arg ++;
  578.             }
  579.             break;
  580.  
  581.         case 'o': /* OR or OLDER_THAN (ot) */
  582.             if (!ptr[1]) /* -o */
  583.             {
  584.             if (cond == -1)
  585.             {
  586.                 fprintf (stderr, "IF: Missing first argument to -o\n");
  587.                 cond = 10;
  588.             }
  589.             else
  590.             {
  591.                 if (cond)
  592.                 stop = 1;
  593.                 arg ++;
  594.             }
  595.             }
  596.             else
  597.             {
  598.             /* Older than */
  599.             if (!found_string)
  600.             {
  601.                 fprintf (stderr, "IF: Missing first argument to -ot\n");
  602.                 cond = 10;
  603.             }
  604.             else
  605.             {
  606.                 cond = compare_dates (arg[-1], arg[1]);
  607.  
  608.                 if (cond != 10)
  609.                 cond = cond < 0;
  610.  
  611.                 arg += 2;
  612.             }
  613.             }
  614.             break;
  615.  
  616.         case 'n': /* "String has non-zero length" or "Not Equal" (ne)
  617.                 or "File1 is newer than File2" (nt) */
  618.             ptr ++;
  619.             switch (*ptr)
  620.             {
  621.             case 0:
  622.             cond = arg[1][0]; /* -n */
  623.             arg += 2;
  624.             break;
  625.  
  626.             case 'e': /* -ne */
  627.             if (found_string)
  628.             {
  629.                 cond = atoi(arg[-1]) != atoi(arg[1]);
  630.                 arg += 2;
  631.             }
  632.             else
  633.             {
  634.                 fprintf (stderr, "IF: Missing first argument to -ne\n");
  635.                 cond = 10;
  636.             }
  637.             break;
  638.  
  639.             case 't': /* -nt */
  640.             /* Newer than */
  641.             if (found_string)
  642.             {
  643.                 cond = compare_dates (arg[-1], arg[1]);
  644.                 arg += 2;
  645.  
  646.                 if (cond != 10)
  647.                 cond = cond > 0;
  648.             }
  649.             else
  650.             {
  651.                 fprintf (stderr, "IF: Missing first argument to -nt\n");
  652.                 cond = 10;
  653.             }
  654.             break;
  655.             }
  656.             break;
  657.  
  658.         case 'z': /* "String has zero length" */
  659.             cond = !arg[1][0];
  660.             arg ++;
  661.             break;
  662.  
  663.         case 'e': /* "File exists" or "Files are the same" (ef) or
  664.                 "Numbers are equal" (eq) */
  665.             ptr ++;
  666.             switch (*ptr)
  667.             {
  668.             case 0:
  669.             cond = exists (arg[1]);
  670.             arg += 2;
  671.             break;
  672.  
  673.             case 'f': {
  674.             BPTR f1, f2;
  675.  
  676.             if (found_string)
  677.             {
  678.                 if (!(f1 = Lock (arg[-1], SHARED_LOCK)) )
  679.                 {
  680.                 PrintFault (IoErr(), arg[-1]);
  681.                 cond = 10;
  682.                 }
  683.                 else
  684.                 {
  685.                 if (!(f2 = Lock (arg[1], SHARED_LOCK)) )
  686.                 {
  687.                     PrintFault (IoErr(), arg[1]);
  688.                     cond = 10;
  689.                 }
  690.                 else
  691.                 {
  692.                     cond = SameLock (f1, f2) == 0;
  693.                     arg += 2;
  694.  
  695.                     UnLock (f2);
  696.                 }
  697.  
  698.                 UnLock (f1);
  699.                 }
  700.             }
  701.             else
  702.             {
  703.                 fprintf (stderr, "IF: Missing first argument to -ef\n");
  704.                 cond = 10;
  705.             }
  706.  
  707.             break; }
  708.             case 'q':
  709.             if (found_string)
  710.             {
  711.                 cond = atoi(arg[-1]) == atoi(arg[1]);
  712.                 arg += 2;
  713.             }
  714.             else
  715.             {
  716.                 fprintf (stderr, "IF: Missing first argument to -eq\n");
  717.                 cond = 10;
  718.             }
  719.             break;
  720.             }
  721.             break;
  722.  
  723.         case 'g': /* "I1 >= I2" (ge) or "I1 > I2" (gt) or
  724.                 "FILE exists and is set-group-ID" */
  725.         case 'l': /* "I1 <= I2" (le) or "I1 < I2" (lt) */
  726.             {
  727.             int i1, i2;
  728.  
  729.             if (!ptr[1])
  730.             {
  731.                 cond = FALSE;
  732.                 break;
  733.             }
  734.  
  735.             if (found_string)
  736.             {
  737.                 i1 = atoi(arg[-1]);
  738.                 i2 = atoi(arg[1]);
  739.                 arg += 2;
  740.  
  741.                 cond = (*ptr == 'g') ? i1 > i2 : i1 < i2;
  742.  
  743.                 if (!cond && ptr[1] == 'e')
  744.                 cond = i1 == i2;
  745.             }
  746.             else
  747.             {
  748.                 fprintf (stderr, "IF: Missing first argument to %s\n", *arg);
  749.                 cond = 10;
  750.             }
  751.             }
  752.             break;
  753.  
  754.         case 't': /* standard output is opened on a terminal */
  755.             cond = IsInteractive (Output ()) != 0;
  756.             arg ++;
  757.             break;
  758.  
  759.         /* The next cases are always false due to AmigaDOS */
  760.         case 'S': /* FILE exists and is a socket */
  761.         case 'b': /* FILE exists and is block special */
  762.         case 'c': /* FILE exists and is character special */
  763.         case 'k': /* FILE exists and has its sticky bit set */
  764.         case 'u': /* FILE exists and its set-user-ID bit is set */
  765.             cond = FALSE;
  766.             arg += 2;
  767.             break;
  768.  
  769.         /* The next cases are always true due to AmigaDOS */
  770.         case 'G': /* File exists and is owned by the effective group ID */
  771.         case 'O': /* FILE exists and is owned by the effective user ID */
  772.             cond = TRUE;
  773.             arg += 2;
  774.             break;
  775.  
  776.         case 'L': /* FILE exists and is a symbolic link */
  777.         case 'p': /* FILE exists and is a named pipe */
  778.         case 'd': /* FILE exists and is a directory */
  779.         case 'f': /* FILE exists and is a regular file */
  780.         case 's': /* FILE exists and has a size greater than zero */
  781.         case 'r': /* FILE exists and is readable */
  782.         case 'w': /* FILE exists and is writable */
  783.         case 'x': /* FILE exists and is executable */
  784.         {
  785.             __aligned struct FileInfoBlock fib;
  786.             BPTR lock;
  787.  
  788.             lock = Lock (arg[1], SHARED_LOCK);
  789.  
  790.             if (lock)
  791.             {
  792.             if (Examine (lock, &fib))
  793.             {
  794.                 switch (*ptr)
  795.                 {
  796.                 case 'L': /* symbolic link */
  797.                 cond = fib.fib_DirEntryType == ST_LINKFILE ||
  798.                     fib.fib_DirEntryType == ST_LINKDIR ||
  799.                     fib.fib_DirEntryType == ST_SOFTLINK;
  800.                 break;
  801.  
  802.                 case 'p': /* named pipe */
  803.                 cond = fib.fib_DirEntryType == ST_PIPEFILE;
  804.                 break;
  805.  
  806.                 case 'd': /* directory */
  807.                 cond = fib.fib_DirEntryType == ST_ROOT ||
  808.                     fib.fib_DirEntryType == ST_USERDIR;
  809.                 break;
  810.  
  811.                 case 'f': /* regular file */
  812.                 cond = fib.fib_DirEntryType == ST_FILE;
  813.                 break;
  814.  
  815.                 case 's': /* size greater than zero */
  816.                 cond = fib.fib_DirEntryType == ST_FILE &&
  817.                     fib.fib_Size;
  818.                 break;
  819.  
  820.                 case 'r': /* readable */
  821.                 cond = !(fib.fib_Protection & FIBF_READ);
  822.                 break;
  823.  
  824.                 case 'w': /* writable */
  825.                 cond = !(fib.fib_Protection & FIBF_WRITE);
  826.                 break;
  827.  
  828.                 case 'x': /* executable */
  829.                 cond = !(fib.fib_Protection & FIBF_EXECUTE) ||
  830.                     (fib.fib_Protection & FIBF_SCRIPT);
  831.                 break;
  832.                 } /* switch */
  833.             }
  834.             else
  835.             {
  836.                 fprintf (stderr, "IF TEST ... %s %s:", arg[0],
  837.                 arg[1]);
  838.                 PrintFault (IoErr(), NULL);
  839.                 cond = 10;
  840.             }
  841.  
  842.             UnLock (lock);
  843.             }
  844.             else
  845.             cond = FALSE;
  846.  
  847.             arg += 2;
  848.         } /* case */
  849.  
  850.         } /* switch */
  851.         } /* if */
  852.         found_string = FALSE;
  853.     }
  854.     else if ((*arg)[0])
  855.     {
  856.         cond = 1;
  857.         if (!found_string)
  858.         found_string = TRUE;
  859.         else
  860.         {
  861.         fprintf (stderr, "IF TEST: Unexpected argument \"%s\"\n",
  862.             *arg);
  863.         cond = 10;
  864.         }
  865.         arg ++;
  866.     }
  867.     else
  868.     {
  869.         fprintf (stderr, "IF TEST: Unexpected empty argument\n");
  870.         cond = 10;
  871.     }
  872.     }
  873.  
  874.     /* If we terminated early, skip until a ) or ] */
  875.     if (stop)
  876.     {
  877.     while (*arg
  878.         && !((*arg)[0] == ')' && !(*arg)[1])
  879.         && !((*arg)[0] == ']' && !(*arg)[1])
  880.         )
  881.     {
  882.         arg ++;
  883.     }
  884.     }
  885.  
  886.     *args = arg;
  887.  
  888.     if (cond == -1)
  889.     {
  890.     fprintf (stderr, "IF TEST: Missing arguments\n");
  891.     cond = 10;
  892.     }
  893.  
  894.     if (cond > 5)
  895.     return cond;
  896.  
  897.     return not ? !cond : cond;
  898. } /* test */
  899.  
  900. int test_unix (struct IfArgs * args)
  901. {
  902.     char ** arg = args->args;
  903.  
  904.     if (!arg)
  905.     {
  906.     fprintf (stderr, "Missing arguments for UN*X-like IF\n");
  907.     return 10;
  908.     }
  909.  
  910.     if (args->test) /* if test is set, implicitly run TEST */
  911.     {
  912.     return test (&arg);
  913.     }
  914.     else /* run all arguments as a command and examine the result */
  915.     {
  916.     int t;
  917.  
  918.     for (t=0; arg[t]; t++)
  919.     {
  920.         if (arg[t][0] == ';' && !arg[t][1])
  921.         break;
  922.     }
  923.  
  924.     return execute_command (t, arg) == 0;
  925.     }
  926.  
  927.     return 0;
  928. } /* test_unix */
  929.  
  930.